package net.bcxuexi.socket.stream.inhandle;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import net.bcxuexi.exception.MyException;
import net.bcxuexi.socket.SocketManager;
import net.bcxuexi.socket.model.IPort;
import net.bcxuexi.socket.stream.StreamData;
import net.bcxuexi.socket.stream.outwrap.OutputDataWrap;
import net.bcxuexi.tools.MyLog;

/**
 * 控制信息输入流数据处理
 */
public class ControlInputStreamHandler extends AbstractInputStreamHandler {


	public ControlInputStreamHandler() {
	}

	@Override
	public void handle() {
		StreamData streamData = null;// 待处理数据

		if (streamData == null) {
			try {
				streamData = take();// 从阻塞队列中取数据，可能会被阻塞
			} catch (InterruptedException e) {
				// 没有取到数据
				return;
			}
		}

		if (streamData == null) {
			MyLog.info("ControlInputStreamHandler队列为空，休息！");
			return;
		}
		// 数据处理
		process(streamData);
		try {
			sleep(80);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 控制信息都是xml的数据，根据根节点进行相应的处理
	 * 
	 * @param streamData
	 */
	private void process(StreamData streamData) {
		InputStream inputStream = new ByteArrayInputStream(streamData.data, 1,
				streamData.total-1);
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		try {
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document doc = builder.parse(inputStream);
			String rootName = doc.getDocumentElement().getNodeName();
			
			if("connId".equals(rootName)){//收到服务器的connId
				System.out.println("接收到控制消息根节点="+rootName);
				connIdProcess(streamData, doc);
			}else if("sendPortToClient".equals(rootName)){
				System.out.println("接收到控制消息根节点="+rootName);
				sendPortToClient(streamData, doc);
			}else if("proxyClosed".equals(rootName)){
				System.out.println("接收到控制消息根节点="+rootName);
				proxyClosed(streamData, doc);
			}else if("heartbeat".equals(rootName)){
				
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 接收服务器connId之后，客户端再次把connId发送给服务器，确认连接建立；并更新socket的connId
	 * @param streamData
	 * @param doc
	 */
	private void connIdProcess(StreamData streamData,Document doc){
		NodeList nodeList = doc.getElementsByTagName("connId");
		
		if(nodeList!=null){
			String connId = nodeList.item(0).getTextContent();
			MyLog.info("收到服务器发送的connId"+connId);
			//发送连接请求信息
			OutputDataWrap outputDataWrap = new OutputDataWrap();
			StreamData outputStreamData = outputDataWrap.csConnId(streamData.getSocketModel(), connId);
			try {
				MyLog.info("发送connId,确认连接建立");
				streamData.getSocketModel().getWriteStream().addData(outputStreamData);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else{
			//关闭链接
			streamData.getSocketModel().closeSocket("connId错误，关闭socket服务。"+streamData.getSocketModel().toString());
		}
	}
	/**
	 * 接收到服务器发送过来的端口信息。
	 * 每一个端口需要创建两个socket，一个连接内网端口，一个连接服务器
	 * @param streamData
	 * @param doc
	 */
	private void sendPortToClient(StreamData streamData,Document doc){
		NodeList iportNodeList = doc.getElementsByTagName("iport");
		if(iportNodeList==null){
			return;
		}
		List<IPort> iports = new ArrayList<IPort>();
		for(int i=0;i<iportNodeList.getLength();i++){
			Node iportNode = iportNodeList.item(i);
			NodeList childNodes = iportNode.getChildNodes();
			int proxy = -1;
			String innerIp="";
			int innerPort = -1;
			String serverSocketIp = "";
			int serverSocketPort = -1;
			for(int j=0;j<childNodes.getLength();j++){
				Node child = childNodes.item(j);
				String nodeName = child.getNodeName();
				String nodeValue = child.getTextContent();
				if("proxy".equals(nodeName)){
					proxy = Integer.valueOf(nodeValue);
				}else if("innerIp".equals(nodeName)){
					innerIp = nodeValue;
				}else if("innerPort".equals(nodeName)){
					innerPort = Integer.valueOf(nodeValue);
				}else if("serverDataIp".equals(nodeName)){
					serverSocketIp = nodeValue;
				}else if("serverDataPort".equals(nodeName)){
					serverSocketPort = Integer.valueOf(nodeValue);
				}
			}
			IPort iport = new IPort(proxy, innerIp, innerPort, serverSocketIp, serverSocketPort);
			iports.add(iport);
		}
		//添加iports
		SocketManager.getInstance().addIports(iports);
	}
	/**
	 * 接收服务器proxyClosed之后，客户端关闭对应的inner socket
	 * @param streamData
	 * @param doc
	 */
	private void proxyClosed(StreamData streamData,Document doc){
		NodeList nodeList = doc.getElementsByTagName("proxyConnId");
		
		if(nodeList!=null){
			String connId = nodeList.item(0).getTextContent();
			MyLog.info("收到服务器发送的proxyClosed消息proxy connId="+connId);
			//关闭对应inner socket
			SocketManager.getInstance().closeInnerSocketByProxyConnId(connId);
		}
	}
}
